package util

import (
	"crypto/sha256"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"github.com/pkg/errors"
	"github.com/spf13/cast"
	"math/rand"
	"net/url"
	"nft-server/common"
	"time"
)

const (
	WSSE_HEADER_FORMAT        = "UsernameToken Username=\"%s\",PasswordDigest=\"%s\",Nonce=\"%s\",Created=\"%s\""
	VerCodeExpireTimeMinute   = 5
	VerCodeCooldownTimeMinute = 1
	VerCodeLength             = 6
	PhoneNumRege              = "^[1][3,4,5,6,7,8,9][0-9]{9}$"
	PhoneNumLen               = 11
)

func GetPhoneVerificationFromRedisValue(redisValue string) (*common.PhoneVerificationInfo, error) {
	verificationInfo := new(common.PhoneVerificationInfo)
	err := json.Unmarshal([]byte(redisValue), verificationInfo)
	if err != nil {
		return nil, err
	}
	return verificationInfo, nil
}

func BuildPhoneVerificationValueForRedis(phi *common.PhoneVerificationInfo) (string, error) {
	data, err := json.Marshal(*phi)
	if err != nil {
		return "", err
	}
	return cast.ToString(data), nil
}

func GenerateVerificationCode(n int) string {
	verCode := ""
	rand.Seed(time.Now().Unix())
	for i := 0; i < n; i++ {
		verCode = fmt.Sprintf("%s%d", verCode, rand.Intn(10))
	}
	return verCode
}

func BuildRequestBody(sender, receiver, templateId, templateParas, statusCallBack, signature string) string {
	param := "from=" + url.QueryEscape(sender) + "&to=" + url.QueryEscape(receiver) + "&templateId=" + url.QueryEscape(templateId)
	if templateParas != "" {
		param += "&templateParas=" + url.QueryEscape(templateParas)
	}
	if statusCallBack != "" {
		param += "&statusCallback=" + url.QueryEscape(statusCallBack)
	}
	if signature != "" {
		param += "&signature=" + url.QueryEscape(signature)
	}
	return param
}

func BuildWsseHeader(appKey, appSecret string) (string, error) {
	var cTime = time.Now().Format("2006-01-02T15:04:05Z")
	nonce := GetUUIDNotCrossbar()

	h := sha256.New()
	_, err := h.Write([]byte(nonce + cTime + appSecret))
	if err != nil {
		return "", err
	}
	passwordDigestBase64Str := base64.StdEncoding.EncodeToString(h.Sum(nil))

	return fmt.Sprintf(WSSE_HEADER_FORMAT, appKey, passwordDigestBase64Str, nonce, cTime), nil
}

// JudgeInputPhoneAndVerValid 判断是否有输入电话号码和验证码，且是否合规, 即是否存在且合法
func JudgeInputPhoneAndVerValid(phoneNumber, inputVerificationCode string) (exists, valid bool, err error) {
	if len(phoneNumber) == 0 { //允许同时不输入的情况
		if len(inputVerificationCode) != 0 {
			return false, false, nil
		}
		return false, true, nil
	}
	if len(inputVerificationCode) != VerCodeLength {
		return true, false, nil
	}
	phoneCheck, err := MatchStr(PhoneNumRege, phoneNumber)
	if err != nil {
		return true, false, errors.Errorf("Judge Input PhoneAndVer error: %v", err)
	}
	if !phoneCheck {
		return true, false, nil
	}
	return true, true, nil
}
